package com.spi.soconversion.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.ExecutionException;

import com.spi.soconversion.base.SOCException;
import com.spi.soconversion.jmsqueue.JMSQueue;
import com.spi.soconversion.jmsqueue.JMSQueueProcessor;
import com.spi.soconversion.jmsqueue.SOCListableThread;

public class SOCJMSControllerTest {
	
	private String d_logFileDirectory;
	private SOCFileWriter d_FileWriter;
	private String d_logFileName;
	private String d_xmlOutputDirectory;
	private String d_host;
	private String d_user;
	private String d_password;
	private String d_service;
	private int d_batchNum = 0;
	private String d_conversionType;
	private List<String> listedDir= new ArrayList<String>();
	private Timestamp startTime;
	private Timestamp endTime;
	
	public static void main(String[] args) {
		SOCJMSControllerTest controller = new SOCJMSControllerTest();
		try {			

			if (args == null) {
				throw new SOCException(ErrorMessageReader
						.getError(ErrorConstants.MISSING_INPUT_PARAMETERS));
			}
			if (args.length != 1) {
				throw new SOCException(
						ErrorMessageReader
						.getError(ErrorConstants.MISSING_CONFIG_PROPERTY_FILE));
			}
			if (!args[0].endsWith(".properties")) {
				throw new SOCException(
						ErrorMessageReader
						.getError(ErrorConstants.INVALID_CONFIG_PROPERTY_FILE));
			}

			controller.init(args[0]);
			controller.getListedDirectories();
			controller.sendFileToJMSQueue();

		} catch (SOCException soe) {

			System.out.println(
					SOCConstants.NEW_LINE
					+ SOCConstants.CONVERSION_NOT_PERFORM_QUEUE
					+ SOCConstants.NEW_LINE
					+ soe.getMessage());
			soe.printStackTrace();
			System.exit(1);
		}
		finally{
			try {
				controller.renameLogFile();
				controller.closeFiles();
				DBConnection.closeConnection();
			} catch (SOCException soe) {
				System.out.println(
						SOCConstants.NEW_LINE
						+ SOCConstants.CONVERSION_NOT_PERFORM_QUEUE
						+ SOCConstants.NEW_LINE
						+ soe.getMessage());
				soe.printStackTrace();
				System.exit(1);
			}
		}
	}
	
	private void init(String propertyFilePath) throws SOCException {
		Properties props = new Properties();
		
		try {
			props.load(new FileInputStream(propertyFilePath));
		} catch (IOException e) {
			throw new SOCException("I/O Exception occurred while reading file - "+propertyFilePath);
		}	
		d_logFileDirectory = props.getProperty("logdirectoryPath");
		if(d_logFileDirectory==null)
		{
			throw new SOCException(
					ErrorMessageReader.getError(
							ErrorConstants.MISSING_LOG_DIRECTORY));
		}
		if(!SOCUtility.checkDirectory(d_logFileDirectory))
		{
			throw new SOCException(
					ErrorMessageReader.getError(
							ErrorConstants.INVALID_OUTPUT_DIRECTORY)+d_logFileDirectory);
		}

		d_FileWriter = new SOCFileWriter();
		String timeStamp =  SOCUtility.dateSuffix();

		d_logFileName = d_logFileDirectory	+ SOCConstants.DELIMITER+SOCConstants.JMS_QUEUE_LOG_FILE+ SOCConstants.UNDERSCORE + timeStamp+ SOCConstants.LOG_FILE_EXTN;

		d_xmlOutputDirectory = props.getProperty("xmldirectoryPath");
		if(d_xmlOutputDirectory==null)
		{
			d_FileWriter.write(d_logFileName, SOCUtility.writeLogMessage(ErrorMessageReader.getError(
					ErrorConstants.MISSING_XML_DIRECTORY)));
			throw new SOCException(
					ErrorMessageReader.getError(
							ErrorConstants.MISSING_XML_DIRECTORY));
		}
		if(!SOCUtility.checkDirectory(d_xmlOutputDirectory))
		{
			d_FileWriter.write(d_logFileName, SOCUtility.writeLogMessage(ErrorMessageReader.getError(
					ErrorConstants.INVALID_OUTPUT_DIRECTORY)+d_xmlOutputDirectory));
			throw new SOCException(
					ErrorMessageReader.getError(
							ErrorConstants.INVALID_OUTPUT_DIRECTORY)+d_xmlOutputDirectory);
		}		

		d_user = props.getProperty("dbuser");
		if(d_user==null)
		{
			d_FileWriter.write(d_logFileName, SOCUtility.writeLogMessage(ErrorMessageReader.getError(
					ErrorConstants.MISSING_DATABASE_USER)));
			throw new SOCException(
					ErrorMessageReader.getError(
							ErrorConstants.MISSING_DATABASE_USER));
		}

		d_password = props.getProperty("dbpassword");
		if(d_password==null)
		{
			d_FileWriter.write(d_logFileName, SOCUtility.writeLogMessage(ErrorMessageReader.getError(
					ErrorConstants.MISSING_DATABASE_PASSWORD)));
			throw new SOCException(
					ErrorMessageReader.getError(
							ErrorConstants.MISSING_DATABASE_PASSWORD));
		}
		d_host = props.getProperty("dbhost");
		if(d_host==null)
		{
			d_FileWriter.write(d_logFileName, SOCUtility.writeLogMessage(ErrorMessageReader.getError(
					ErrorConstants.MISSING_DATABASE_HOST)));
			throw new SOCException(
					ErrorMessageReader.getError(
							ErrorConstants.MISSING_DATABASE_HOST));
		}

		d_service = props.getProperty("dbservice");
		if(d_service==null)
		{
			d_FileWriter.write(d_logFileName, SOCUtility.writeLogMessage(ErrorMessageReader.getError(
					ErrorConstants.MISSING_DATABASE_SERVICE)));
			throw new SOCException(
					ErrorMessageReader.getError(
							ErrorConstants.MISSING_DATABASE_SERVICE));
		}
		String batchNum = props.getProperty("batchNum");
		if(batchNum==null)
		{
			d_FileWriter.write(d_logFileName, SOCUtility.writeLogMessage(ErrorMessageReader.getError(
					ErrorConstants.MISSING_BATCH_NUMBER)));
			throw new SOCException(
					ErrorMessageReader.getError(
							ErrorConstants.MISSING_BATCH_NUMBER));
		}
		try {

			d_batchNum=Integer.parseInt(batchNum);

		} catch (NumberFormatException nfe) {
			d_FileWriter.write(d_logFileName, SOCUtility.writeLogMessage(ErrorMessageReader.getError(
					ErrorConstants.INVALID_BATCH_NUMBER)+ batchNum));
			throw new SOCException(
					ErrorMessageReader.getError(
							ErrorConstants.INVALID_BATCH_NUMBER)+batchNum,nfe);
		}
		if(d_batchNum<=0)
		{
			d_FileWriter.write(d_logFileName, SOCUtility.writeLogMessage(ErrorMessageReader.getError(
					ErrorConstants.INVALID_BATCH_NUMBER_NOT_POSITIVE_NUMBER) + batchNum));
			throw new SOCException(
					ErrorMessageReader.getError(
							ErrorConstants.INVALID_BATCH_NUMBER_NOT_POSITIVE_NUMBER)+batchNum);
		}
		
		d_conversionType = props.getProperty("conversionType");
		if(d_conversionType==null)
		{
			d_FileWriter.write(d_logFileName, SOCUtility.writeLogMessage(ErrorMessageReader.getError(
					ErrorConstants.MISSING_CONVERSION_TYPE)));
			throw new SOCException(
					ErrorMessageReader.getError(
							ErrorConstants.MISSING_CONVERSION_TYPE));
		}
		
		DBConnection.getConnection(d_host, d_service, d_user,d_password);
	}

	private void closeFiles() throws SOCException
	{
		if(d_FileWriter!=null)
		{
			d_FileWriter.closeFile(d_logFileName);   
		}
	}
	
	private void renameLogFile() throws SOCException
	{
		//renaming log file
		File logFile = new File(d_logFileName);
		String timeStamp = d_logFileName.substring(d_logFileName.indexOf(SOCConstants.UNDERSCORE), d_logFileName.length());
		String log= SOCConstants.JMS_QUEUE_LOG_FILE+SOCConstants.UNDERSCORE+SOCConstants.BATCH+d_batchNum+timeStamp;
		boolean renameLogFile = false;
		d_FileWriter.closeFile(d_logFileName);		
		renameLogFile=logFile.renameTo(new File(d_logFileDirectory, log));
		
		if(renameLogFile) {
			d_logFileName=d_logFileDirectory+SOCConstants.DELIMITER+log;
		}
		else {
			d_FileWriter.write(d_logFileName, SOCUtility.writeLogMessage(ErrorMessageReader.getError(
					ErrorConstants.FAILED_RENAME_LOG_FILE)+log));
			throw new SOCException(
					ErrorMessageReader.getError(
							ErrorConstants.FAILED_RENAME_LOG_FILE)+log);			
		}		
	}
	
	private void getListedDirectories() throws SOCException
	{
		startTime = new Timestamp(System.currentTimeMillis());
		d_xmlOutputDirectory=d_xmlOutputDirectory+SOCConstants.DELIMITER+SOCConstants.BATCH+SOCConstants.UNDERSCORE+d_batchNum;
		File XMLDirRef= new File(d_xmlOutputDirectory);
		if (!XMLDirRef.exists())
		{
			d_FileWriter.write(d_logFileName, SOCUtility.writeLogMessage(ErrorMessageReader.getError(
					ErrorConstants.BATCH_NOT_EXIST)+d_batchNum));
			throw new SOCException(
					ErrorMessageReader.getError(
							ErrorConstants.BATCH_NOT_EXIST)+d_batchNum);
		}
		d_FileWriter.write(d_logFileName, SOCUtility.writeLogMessage(SOCConstants.JMS_QUEUE_GET_DIR_NAMES_START_PROCESSING+d_xmlOutputDirectory));
		
		File[] subDir=XMLDirRef.listFiles();
		
		if(subDir!=null)

		{
			for(File file : subDir)
			{
				if(file.isDirectory())
				{
					String absolutePath = file.getAbsolutePath();
					// XSD validation not happening for closed sales so there willn't be any good records directory
					if(d_conversionType.equals(ConversionType.INSTALLBASE.getDisplayText()))
					{
						absolutePath=absolutePath+SOCConstants.DELIMITER+SOCConstants.DIR_NAME_GOOD_RECORDS;
					}
					listedDir.add(absolutePath);
				}
			}
		}
		
		d_FileWriter.write(d_logFileName, SOCUtility.writeLogMessage(SOCConstants.JMS_QUEUE_GET_DIR_NAMES_END_PROCESSING+d_xmlOutputDirectory));
	}
	
	private void sendFileToJMSQueue() throws SOCException
	{
		if(listedDir!=null && listedDir.size()>0)
		{
			d_FileWriter.write(d_logFileName, SOCUtility.writeLogMessage(SOCConstants.JMS_QUEUE_START_PROCESSING));
			JMSQueue jmsQueueHandler = new JMSQueue(d_conversionType,d_logFileName,d_FileWriter);
			jmsQueueHandler.getJMSClient();
			List<SOCListableThread<JMSQueueProcessor>> threads = new ArrayList<SOCListableThread<JMSQueueProcessor>>();
			for(String dirName: listedDir)
			{
				SOCListableThread<JMSQueueProcessor> thread = new SOCListableThread<JMSQueueProcessor>(new JMSQueueProcessor(jmsQueueHandler,dirName,d_logFileName,d_FileWriter));

				threads.add(thread);
				thread.start();		
			}
			StringBuilder succesMsg = new StringBuilder();
			StringBuilder failureMsg = new StringBuilder();
			for (SOCListableThread<JMSQueueProcessor> thread : threads) {
				try {
					boolean result = thread.get();
					if(result) {
						if(succesMsg.length()>0) {
							succesMsg.append(SOCConstants.COMMA+thread.getDirName());							
						}
						else {
							succesMsg.append(thread.getDirName());	
						}
					}
					else {
						if(failureMsg.length()>0) {
							failureMsg.append(SOCConstants.COMMA+thread.getDirName());							
						}
						else {
							failureMsg.append(thread.getDirName());	
						}
						d_FileWriter.write(d_logFileName, SOCUtility.writeLogMessage(ErrorMessageReader.getError(
								ErrorConstants.JMS_PUSH_FAIL_FOR_DIR)+thread.getDirName()));					
					}
				} catch (ExecutionException e) {
					e.printStackTrace();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				endTime = new Timestamp(System.currentTimeMillis());
				updateJMSQueueInfo(succesMsg.toString(), failureMsg.toString());
				
			}
			d_FileWriter.write(d_logFileName, SOCUtility.writeLogMessage(SOCConstants.JMS_QUEUE_END_PROCESSING));
		}
		else
		{
			d_FileWriter.write(d_logFileName, SOCUtility.writeLogMessage(SOCConstants.NO_XML_SUB_DIRS_FOR_JMS_QUEUE+d_xmlOutputDirectory));
		}
		
	}
	
	public void updateJMSQueueInfo(String successMsg, String failureMsg) throws SOCException
    {
    	String batchUpdateQuery = QueryReader.getQuery(QueryConstants.INSERT_CONVERSION_JMS_STATISTICS_QUERY);
    	PreparedStatement batchStmt=null;
    	int recordCount=0;
    	try
		{
    		batchStmt=DBConnection.getConnection().prepareStatement(batchUpdateQuery);
    		batchStmt.setString(1, d_conversionType);
    		batchStmt.setInt(2, d_batchNum);
    		batchStmt.setTimestamp(3,startTime);
    		batchStmt.setTimestamp(4, endTime);    		
    		batchStmt.setString(5, successMsg);
    		batchStmt.setString(6, failureMsg);
    		
    		
    		recordCount=batchStmt.executeUpdate();
    		if(recordCount==0)
			{
				d_FileWriter.write(d_logFileName, SOCUtility.writeLogMessage(ErrorMessageReader.getError(
	            				ErrorConstants.NO_RECORD_POPULATION_TBL_JMS_QUEUE_STATISTICS)));
				throw new SOCException(
	            		ErrorMessageReader.getError(
	            				ErrorConstants.NO_RECORD_POPULATION_TBL_JMS_QUEUE_STATISTICS));
			}	
		}
		catch(SQLException sqle)
		{
			d_FileWriter.write(d_logFileName, SOCUtility.writeLogMessage(ErrorMessageReader.getError(
    				ErrorConstants.FAILED_UPDATE_JMS_STATISTICS_INFO)+SOCConstants.NEW_LINE+sqle.getMessage()));
			throw new SOCException(
            		ErrorMessageReader.getError(
            				ErrorConstants.FAILED_UPDATE_JMS_STATISTICS_INFO) ,sqle);
    		
		}	
    }

}